﻿/******************************************************************************
 * This file is part of libemb.
 *
 * libemb is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * libemb is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with libemb.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Project: Embedme
 * Author : FergusZeng
 * Email  : cblock@126.com
 * git	  : https://git.oschina.net/cblock/embedme
 * Copyright 2014~2017 @ ShenZhen ,China
*******************************************************************************/
#include "Mutex.h"

#include <sys/errno.h>

namespace libemb{
MutexLock::MutexLock()
{
	pthread_mutex_init(&m_mutex,NULL);
}

MutexLock::~MutexLock()
{
	pthread_mutex_destroy(&m_mutex);
}

/**
 *  \brief  互斥锁上锁
 *  \note   none
 */
int MutexLock::lock()
{
	return pthread_mutex_lock(&m_mutex);
}
/**
 *  \brief  互斥锁解锁
 *  \note   none
 */
int MutexLock::unLock()
{
	return pthread_mutex_unlock(&m_mutex);
}
/**
 *  \brief  互斥锁尝试上锁
 *  \note   none
 */
int MutexLock::tryLock()
{
	return pthread_mutex_trylock(&m_mutex);
}

AutoLock::AutoLock(MutexLock* mutexLock):
m_mutexLock(mutexLock)
{
	m_mutexLock->lock();
}

AutoLock::~AutoLock()
{
	m_mutexLock->unLock();
}

MutexCond::MutexCond(MutexLock* lock)
{
    m_lock = lock;
    #if defined OS_CYGWIN || defined OS_UNIX
    pthread_condattr_init(&m_condAttr); 
    pthread_condattr_setclock(&m_condAttr, CLOCK_MONOTONIC);
    #endif
    pthread_cond_init(&m_cond,&m_condAttr);
}

MutexCond::~MutexCond()
{
}
/**
 *  \brief  等待条件变量
 *  \param  int second,超时时间,<0时阻塞等待,>=0时等待second
 *  \return 成功等到条件变量返回STATUS_OK,超时返回STATUS_TIMEOUT,失败返回STATUS_ERROR
 *  \note   执行该方法后线程会阻塞并释放锁,一直等待条件变量或者超时.
 */
int MutexCond::wait(int seconds)
{
    int ret;
    if (seconds>=0){
        struct timespec tv;
        clock_gettime(CLOCK_MONOTONIC, &tv);
        tv.tv_sec += seconds;
    #if defined OS_CYGWIN || defined OS_UNIX
        ret = pthread_cond_timedwait(&m_cond,&(m_lock->m_mutex),&tv);
    #else
        ret = pthread_cond_timedwait_monotonic_np(&m_cond,&(m_lock->m_mutex),&tv);/* for Android bionic pthread */
    #endif
    } else {
        ret = pthread_cond_wait(&m_cond,&(m_lock->m_mutex));
    }
    switch (ret) {
    case 0:
        return STATUS_OK;
    case ETIMEDOUT:
        return STATUS_TIMEOUT;
    default:
        return STATUS_ERROR;
    }
}
/**
 *  \brief  满足条件变量,通知等待者
 *  \note   none
 */
int MutexCond::meet()
{
    return (pthread_cond_signal(&m_cond)==0)?STATUS_OK:STATUS_ERROR;

}
}